// 要的数字和文本分开处理
// function padLeft(padding: number| string, input: string):string {
//     if(typeof padding === "number") {
//         // 只有数字才有的函数
//         return " ".repeat(padding) + input;
//     }
//     return padding + input;
// }

/**
 * typeof 支持的类别
 * "string"
 * "number"
 * "bigint"
 * "boolean"
 * "symbol"
 * "undefined"
 * "object"
 * "function"
 */

function printAll(strs:string | string[] | null) {
    if(typeof strs === "object") {
        // strs可能是null
        if(strs !== null) {
            for (const s of strs) {
                console.log(s);
            }
        }
    } else if(typeof strs == "string") {
        console.log(strs);
    } else {
        // do nothing
    }
}
// 这里的if是判断是不是传值了，没有传值就走return "Nobody's here. :("
// function getUserOnlineMessage(numbersOnline: number) {
//     if(numbersOnline) {
//         return `There are ${numbersOnline} online now!`;
//     }
//     return "Nobody's here. :(";
// }


function getUserOnlineMessage(numbersOnline: string) {
    if(numbersOnline) {
        return `There are ${numbersOnline} online now!`;
    }
    return "Nobody's here. :(";
}
/**
 * 编译出来的代码都是一样的
 * 
 * 0
 * NaN
 * ""
 * 0n
 * null
 * undefined
 * 
 * false就是正常的if else走了
 */ 
/*
function getUserOnlineMessage(numbersOnline) {
    if (numbersOnline) {
        return "There are ".concat(numbersOnline, " online now!");
    }
    return "Nobody's here. :(";
}
*/
Boolean("hello");
!! "world";

function printAll1(strs:string | string[] | null) {
    // strs可能是null 在if的条件中会转为boolean类型
    if(strs && typeof strs === "object") {
        for (const s of strs) {
            console.log(s);
        }
    } else if(typeof strs == "string") {
        console.log(strs);
    } else {
        // do nothing
    }
}

// 也可以用!

function multiplyAll(
    values: number[] | undefined,
    factor: number
): number[] | undefined {
    if(!values) {
        return values;
    } else {
        return values.map((x)=> x * factor);
    }
}
// 等于符号缩小
/**
 * 在TypeScript中，=== 和 !== 是严格相等和严格不相等的比较运算符，而 == 和 != 是非严格相等和非严格不相等的比较运算符。

严格相等（===）和严格不相等（!==）运算符比较两个值的类型和值是否完全相等。如果两个值的类型和值都相等，则返回true，否则返回false。严格相等和严格不相等运算符不会进行类型转换。

非严格相等（==）和非严格不相等（!=）运算符在比较之前，会进行类型转换。如果两个值的类型不同，会尝试将它们转换为相同类型，然后再进行比较。非严格相等和非严格不相等运算符会对操作数进行隐式类型转换，这可能会导致一些意外的结果。

因此，在使用比较运算符时，建议使用严格相等和严格不相等运算符（=== 和 !==），以避免类型转换带来的问题。
 */
function example1(x:string | number, y: string | boolean) {
    if(x === y) {
        // We can now call any 'string' method on 'x' or 'y'
        x.toUpperCase();
        y.toLowerCase();
    } else {
        // x is string | number
        console.log(x);
        // y is string | boolean
        console.log(y);
    }
}

function printAll2(strs:string | string[] | null) {
    // strs可能是null 在if的条件中会转为boolean类型
    if(strs !== null) {
        if(typeof strs === "object") {
            for (const s of strs) {
                console.log(s);
            }
        } else if(typeof strs == "string") {
            console.log(strs);
        } 
    }
   
}

interface Container {
    value: number | null | undefined;
}

function multiplyAll3(container:Container, factor:number) {
    if(container.value != null) {
        console.log(container.value);
        container.value *= factor;
    }
}

type Fish = {swim:() => void; name: string;};
type Bird = {fly:() => void; name: string};

function move(animal:Fish | Bird) {
    if("swim" in animal) {
        return animal.swim();
    }
    return animal.fly();
}

type Human = {swim?:()=>void; fly?:() => void};
function move2(animal:Fish | Bird | Human) {
    if("swim" in animal) {
        animal;
    } else {
        animal;
    }
}
// 确定类型
function logValue(x:Date | string) {
    if(x instanceof Date) {
        console.log(x.toUTCString());
    } else {
        console.log(x.toUpperCase())
    }
}

let x = Math.random() < 0.5 ? 10 :"Hello world!";

x = 1;

console.log(x);

x = "goodbye!";
// x = true
console.log(x);
// 控制流分析
function padLeft(padding:number | string, input:string) {
    if (typeof padding == "number") {
        return " ".repeat(padding) + input;
    } 
    return padding + input;
}

function example2() {
    let x:string | number | boolean;
    x = Math.random() < 0.5;
    // boolean
    console.log(x);
    if(Math.random() < 0.5) {
        x = "hello";
    } else {
        x = 100;
        console.log(x);
    }
    // 预测为 number| string类型
    return x;
}
// type 预测
function isFish(pet:Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

declare function getSmallPet(): Fish | Bird;

let pet = getSmallPet();


if(isFish(pet)) {
    pet.swim();
} else {
    pet.fly();
}

const zoo: (Fish | Bird) [] = [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[] = zoo.filter(isFish);
// or equivalenty
const underWater2: Fish[] = zoo.filter(isFish) as Fish[];
// the predicate may need repeationg for more complex eaxmple
const underWater3: Fish[] = zoo.filter((pet) : pet is Fish => {
    if(pet.name === "sharekey") return false;
    return isFish(pet)
});

interface Shape {
    kind: "circle" | "square";
    radius?: number;
    sideLength?: number;
}

function handleShape(shape: Shape) {
    // This comparison appears to be unintentional because the types '"sircle" | "square"' and 
    // '"rect"' have no overlap.
    // if(shape.kind === "rect") {
        /// 
    // }
}

function getArea(shape: Shape) {
    // shape.radius' is possibly 'undefined'
    // return Math.PI * shape.radius ** 2
}

function getArea1(shape: Shape) {
    if(shape.kind === "circle") {
        //'shape.radius' is possibly 'undefined'.
        // 打！后
        return Math.PI * shape.radius! ** 2
    }
}

interface Circle {
    kind: "Circle";
    radius: number;
}

interface Square {
    kind: "Square";
    sideLength: number;
}

type Shape1 = Circle | Square;
function getArea2(shape: Shape1) {
    // Property 'radius' does not exist on type 'Shape1'.
    //   Property 'radius' does not exist on type 'Square'.
    // 
    // return Math.PI * shape.radius ** 2
}

function getArea3(shape: Shape1) {
    if(shape.kind === "Circle") {
        // (parameter) shape: Circle
        return Math.PI * shape.radius ** 2
    }
}

function getArea4(shape: Shape1) {
    switch(shape.kind) {
        case "Circle":
            // (parameter) shape: Circle
            return Math.PI * shape.radius ** 2;
        case "Square":
            // (parameter) shape: Square
            return shape.sideLength ** 2;
        default:
            const _exhaustiveCheck: never = shape;
            return _exhaustiveCheck;
    }
}


interface Triangle {
    kind: "Triangle";
    sideLength: number;
}

type Shape2 = Circle | Square | Triangle;

function getArea5(shape: Shape2) {
    switch(shape.kind) {
        case "Circle":
            // (parameter) shape: Circle
            return Math.PI * shape.radius ** 2;
        case "Square":
            // (parameter) shape: Square
            return shape.sideLength ** 2;
        default:
            // Type 'Triangle' is not assignable to type 'never'.
            // const _exhaustiveCheck: never = shape;
            // return _exhaustiveCheck;
            return shape.sideLength ** 2;
    }
}
// the never type
